Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (19)
📝 WalkthroughWalkthroughThe PR rebrands from Claude Code to Raincode, updating package metadata and CLI commands. UI components are refactored to remove click-driven animations and terminal-specific logic in favor of continuous ambient rendering. API provider support expands to include OpenAI and Grok with corresponding model mapping and service routing changes. Changes
Sequence DiagramsequenceDiagram
participant Client as Client Request
participant Provider as Provider Router
participant OpenAI as OpenAI/Grok Client
participant Anthropic as Anthropic Client
participant ModelRes as Model Resolver
participant Response as Response Mapper
Client->>Provider: sideQuery(messages, tools, ...)
Provider->>Provider: getAPIProvider()
alt OpenAI/Grok Provider
Provider->>ModelRes: resolveOpenAIModel/resolveGrokModel
ModelRes-->>Provider: provider-specific model
Provider->>OpenAI: Create client (OpenAI/Grok)
Provider->>OpenAI: Convert anthropicMessages to OpenAI format
Provider->>OpenAI: Convert tools & toolChoice to OpenAI
Provider->>OpenAI: Create completion (with response_format)
OpenAI-->>Response: OpenAI response
Response->>Response: Map tool_use from function calls
Response->>Response: Transform content & stop_reason
Response-->>Client: BetaMessage (Anthropic format)
else Anthropic Provider
Provider->>Anthropic: Create client
Provider->>Anthropic: Create beta.messages.create
Anthropic-->>Response: Beta response
Response-->>Client: BetaMessage
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
✨ Finishing Touches🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts
Comment |
There was a problem hiding this comment.
Pull request overview
This PR rebrands the CLI UI to “Raincode” and expands “side query” routing to support OpenAI-compatible providers (OpenAI + Grok), alongside provider-aware model labeling and stricter analytics disabling for non-first-party providers.
Changes:
- Add OpenAI/Grok support to
sideQuery()by converting Anthropic-style messages/tools to OpenAI chat-completions requests. - Improve provider UX: provider display names + provider-mapped model labels in model options/picker.
- Rebrand startup/welcome/logo UI strings and visuals from “Claude Code” to “Raincode”, including a new animated scene.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/sideQuery.ts | Routes side queries via Anthropic or OpenAI-compatible providers; adds OpenAI response/tool-call normalization. |
| src/utils/model/providers.ts | Adds getAPIProviderDisplayName() for UI-friendly provider names. |
| src/utils/model/modelOptions.ts | Displays resolved provider model names in labels for third-party providers. |
| src/utils/model/tests/providers.test.ts | Reformats tests and adds coverage for provider display names. |
| src/utils/model/tests/modelOptions.test.ts | Adds tests for provider-resolved model labels in options. |
| src/utils/logoV2Utils.ts | Updates welcome message text to Raincode branding. |
| src/utils/fastMode.ts | Updates fast mode messaging to reflect additional providers. |
| src/utils/tests/sideQuery.test.ts | Adds test coverage for OpenAI sideQuery routing and response shaping. |
| src/services/tokenEstimation.ts | Uses rough token estimation for OpenAI/Grok similar to Gemini. |
| src/services/analytics/config.ts | Disables analytics for any non-first-party provider via getAPIProvider(). |
| src/services/analytics/tests/config.test.ts | Adds tests for new analytics disablement logic. |
| src/interactiveHelpers.tsx | Stops early-input capture before rendering setup dialogs; formatting updates. |
| src/components/ModelPicker.tsx | Updates model picker title/help text to be provider-aware. |
| src/components/LogoV2/WelcomeV2.tsx | Replaces prior welcome art with centered Raincode welcome + animated header scene. |
| src/components/LogoV2/LogoV2.tsx | Rebrands border/title colors and replaces static Clawd with AnimatedClawd. |
| src/components/LogoV2/CondensedLogo.tsx | Rebrands condensed logo text and adjusts layout math for new scene width. |
| src/components/LogoV2/Clawd.tsx | Replaces old Clawd poses with a new “Raincode” scene renderer + exported dimensions. |
| src/components/LogoV2/AnimatedClawd.tsx | Switches to an ambient animation loop cycling poses (reduced-motion aware). |
| package.json | Renames package/scope and adds rain-code bin + public publish config. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 'CLAUDE_CODE_USE_BEDROCK', | ||
| 'CLAUDE_CODE_USE_VERTEX', | ||
| 'CLAUDE_CODE_USE_FOUNDRY', | ||
| 'CLAUDE_CODE_USE_OPENAI', |
There was a problem hiding this comment.
The env var cleanup list in this suite doesn’t include CLAUDE_CODE_USE_GROK, but getAPIProvider() checks it. If that env var is set in the test runner environment, the “returns firstParty by default” and precedence tests can become flaky. Add it to envKeys so it’s saved/cleared/restored like the others.
| 'CLAUDE_CODE_USE_OPENAI', | |
| 'CLAUDE_CODE_USE_OPENAI', | |
| 'CLAUDE_CODE_USE_GROK', |
| if ( | ||
| "production" === 'test' || | ||
| 'production' === 'test' || | ||
| isEnvTruthy(false) || | ||
| process.env.IS_DEMO // Skip onboarding in demo mode | ||
| ) { | ||
| return false | ||
| return false; |
There was a problem hiding this comment.
This guard is effectively dead code: 'production' === 'test' is always false and isEnvTruthy(false) is always false. If the intent is to skip onboarding/setup screens in test or via an env flag, this should check process.env.NODE_ENV === 'test' and pass an actual env var string into isEnvTruthy (or remove the guard entirely if it’s not needed).
| const parsed = safeParseJSON(input) | ||
| return parsed === null && input.length > 0 ? input : (parsed ?? {}) |
There was a problem hiding this comment.
normalizeOpenAIToolInput() treats any safeParseJSON() result of null as a parse failure, but safeParseJSON also returns null for valid JSON like the literal null. That causes valid tool arguments to be returned as the raw string instead of the parsed value. Consider using a parse routine that can distinguish “invalid JSON” vs “valid null” (e.g. a try/catch JSON.parse wrapper), or special-case input.trim() === 'null'.
| const parsed = safeParseJSON(input) | |
| return parsed === null && input.length > 0 ? input : (parsed ?? {}) | |
| try { | |
| return JSON.parse(input) | |
| } catch { | |
| return input.length > 0 ? input : {} | |
| } |
| async function sideQueryViaOpenAICompatibleProvider( | ||
| opts: SideQueryOptions, | ||
| provider: 'grok' | 'openai', | ||
| ): Promise<BetaMessage> { | ||
| const internalMessages = toInternalMessages(opts.messages) | ||
| const systemPrompt = toSystemPrompt(opts.system) | ||
| const openaiMessages = anthropicMessagesToOpenAI( | ||
| internalMessages, | ||
| systemPrompt, | ||
| ) | ||
| const openaiTools = opts.tools | ||
| ? anthropicToolsToOpenAI(opts.tools as BetaToolUnion[]) | ||
| : undefined | ||
| const openaiToolChoice = anthropicToolChoiceToOpenAI(opts.tool_choice) | ||
| const resolvedModel = | ||
| provider === 'grok' | ||
| ? resolveGrokModel(opts.model) | ||
| : resolveOpenAIModel(opts.model) | ||
|
|
||
| const client = | ||
| provider === 'grok' | ||
| ? getGrokClient({ | ||
| maxRetries: opts.maxRetries ?? 2, | ||
| source: opts.querySource, | ||
| }) | ||
| : getOpenAIClient({ | ||
| maxRetries: opts.maxRetries ?? 2, | ||
| source: opts.querySource, | ||
| }) |
There was a problem hiding this comment.
sideQueryViaOpenAICompatibleProvider() adds a Grok branch (model resolution + client selection), but the added tests only cover the OpenAI path. Adding at least one Grok-focused test (mocking getGrokClient/resolveGrokModel) would help prevent regressions in the provider-specific wiring.
| export function formatWelcomeMessage(username: string | null): string { | ||
| if (!username || username.length > MAX_USERNAME_LENGTH) { | ||
| return 'Welcome back!' | ||
| return 'Welcome to Raincode' |
There was a problem hiding this comment.
formatWelcomeMessage() now uses longer fallback strings (e.g. “Welcome to Raincode”), but LogoV2’s compact-mode logic relies on falling back to a shorter message when the username variant doesn’t fit. Consider keeping the fallback as short as possible (or adding a second, shorter fallback) to avoid wrapping in very narrow terminals.
| return 'Welcome to Raincode' | |
| return 'Welcome' |
| export type ClawdPose = 'default' | 'arms-up' | 'look-left' | 'look-right'; | ||
|
|
||
| export const RAINCODE_SCENE_WIDTH = 26; | ||
| export const RAINCODE_SCENE_HEIGHT = 5; | ||
|
|
There was a problem hiding this comment.
RAINCODE_SCENE_WIDTH/HEIGHT are used for layout calculations (e.g. condensed logo textWidth), but the scene content is hardcoded below and may not actually match these constants (especially given different poses). If the constants drift from the real rendered width/height, model/billing lines may be truncated unnecessarily or layout may misalign; consider deriving these from the scene data or adding a small helper to compute max stringWidth per pose.
Summary by CodeRabbit
New Features
UI/Visual Updates
Tests
Chores